﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PmSoft.Utilities
{
    public static class Base64Utilities
    {
        private static int RANGE = 255;

        private static char[] Base64ByteToStr = new char[64]
        {
        '+', 'L', 'Q', 'R', 'S', '3', 'M', 'N', 'w', 'x',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
        'd', 'Y', '1', 'a', 'V', 'W', 'X', 'b', 'c', 'U',
        'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'O', 'P',
        'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', '6', '7',
        'y', 'z', '0', 'Z', '2', 'T', '4', '5', 'm', 'n',
        '8', '9', 'K', '/'
        };

        private static byte[] StrToBase64Byte = new byte[128];

        static Base64Utilities()
        {
            GenerateDecoder();
        }

        private static void GenerateDecoder()
        {
            for (int i = 0; i <= StrToBase64Byte.Length - 1; i++)
            {
                StrToBase64Byte[i] = JavaByteToC(-1);
            }
            for (int j = 0; j <= Base64ByteToStr.Length - 1; j++)
            {
                StrToBase64Byte[(uint)Base64ByteToStr[j]] = (byte)j;
            }
        }

        private static byte JavaByteToC(int i)
        {
            if (i < 0)
            {
                return byte.Parse((i + 256).ToString());
            }
            return byte.Parse(i.ToString());
        }

        private static void ShowDecoder()
        {
            string text = "";
            for (int i = 1; i <= StrToBase64Byte.Length; i++)
            {
                string text2 = text;
                int num = StrToBase64Byte[i - 1];
                text = text2 + num + ",";
                if (i % 10 == 0 || i == StrToBase64Byte.Length)
                {
                    text = "";
                }
            }
        }

        private static int UIntMoveRight(int x, int y)
        {
            int num = int.MaxValue;
            for (int i = 0; i < y; i++)
            {
                x >>= 1;
                x &= num;
            }
            return x;
        }

        public static string Encode(byte[] bytes)
        {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i <= bytes.Length - 1; i += 3)
            {
                byte[] array = new byte[4];
                byte b = 0;
                for (int j = 0; j <= 2; j++)
                {
                    if (i + j <= bytes.Length - 1)
                    {
                        array[j] = (byte)(UIntMoveRight(bytes[i + j] & RANGE, 2 + 2 * j) | b);
                        b = (byte)UIntMoveRight(((bytes[i + j] & RANGE) << 2 + 2 * (2 - j)) & RANGE, 2);
                    }
                    else
                    {
                        array[j] = b;
                        b = 64;
                    }
                }
                array[3] = b;
                for (int k = 0; k <= 3; k++)
                {
                    if (array[k] <= 63)
                    {
                        stringBuilder.Append(Base64ByteToStr[array[k]]);
                    }
                    else
                    {
                        stringBuilder.Append('=');
                    }
                }
            }
            return stringBuilder.ToString();
        }

        public static byte[] Decode(string val)
        {
            MemoryStream memoryStream = new MemoryStream();
            byte[] bytes = Encoding.UTF8.GetBytes(val);
            byte[] array = new byte[bytes.Length];
            for (int i = 0; i <= bytes.Length - 1; i++)
            {
                int num = bytes[i];
                array[i] = StrToBase64Byte[num];
            }
            for (int j = 0; j <= array.Length - 1; j += 4)
            {
                byte[] array2 = new byte[3];
                int num2 = 0;
                for (int k = 0; k <= 2; k++)
                {
                    if (j + k + 1 <= array.Length - 1 && array[j + k + 1] < 128)
                    {
                        byte b = (byte)UIntMoveRight(array[j + k + 1] & RANGE, 2 + 2 * (2 - (k + 1)));
                        array2[k] = (byte)((((array[j + k] & RANGE) << 2 + 2 * k) & RANGE) | b);
                        num2++;
                    }
                }
                for (int l = 0; l <= num2 - 1; l++)
                {
                    memoryStream.WriteByte(array2[l]);
                }
            }
            return memoryStream.ToArray();
        }

        public static byte[] ConverBase64(string data64)
        {
            byte[] data = new byte[0];
            data64 = data64.Replace(" ", "+");
            try
            {
                data = Convert.FromBase64String(data64);

                return data;
            }
            catch
            {
                data = Decode(data64);
            }
            return data;
        }
    }
}
